package com.stack.common.utils;

import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

/**
 * 日期时间工具类
 * Java8 LocalDate LocalTime LocalDateTime
 */
public class DateUtil {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";

    public static final String DEFAULT_DATE_FORMAT2 = "yyyyMMdd";

    public static final String DEFAULT_DATE_FORMAT3 = "yyyy.MM.dd";

    public static final String DEFAULT_DATE_FORMAT4 = "yy.MM.dd";

    public static final String DEFAULT_DATE_FORMAT5 = "yyyy年MM月dd日";

    public static final String DEFAULT_DATE_FORMAT6 = "yyyy/MM/dd";

    public static final String DEFAULT_DATE_FORMAT7 = "yyyy年MM月";

    public static final String DEFAULT_DATE_FORMAT8 = "MM月dd日";

    public static final String DEFAULT_DATE_FORMAT9 = "M月d日";

    public static final String DEFAULT_DATE_FORMAT10 = "yyyyMM";

    public static final String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

    public static final String DEFAULT_DATETIME_FORMAT2 = "yyyyMMddHHmmss";

    public static final String DEFAULT_DATETIME_FORMAT3 = "yyyy/MM/dd HH:mm";

    public static final String DEFAULT_DATETIME_FORMAT4 = "yyyy.MM.dd HH:mm:ss";

    public static final String DEFAULT_DATETIME_FORMAT5 = "yyyy.MM.dd HH:mm";

    public static final String DEFAULT_DATETIME_FORMAT6 = "yyyy-MM-dd HH:mm";

    public static final String DEFAULT_DATETIME_FORMAT7 = "yyyy年MM月dd日 HH:mm";

    public static final String DEFAULT_DATETIME_FORMAT9 = "yyyyMMddHHmmssSSS";

    public static final String DEFAULT_DATETIME_FORMAT10 = "yyyy-MM-dd'T'HH:mm:ssXXX";

    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    public static final String DEFAULT_DAY_TIME_START = " 00:00:00";

    public static final String DEFAULT_DAY_TIME_END = " 23:59:59";

    private DateUtil() {
    }

    public static class Holder {
        private static final DateUtil instance = new DateUtil();
    }

    public static DateUtil getInstance() {
        return Holder.instance;
    }

    /**
     * 获取系统当前日期时间
     *
     * @return
     */
    public LocalDateTime getNow() {
        return LocalDateTime.now();
    }

    /**
     * 获取默认格式的系统当前日期时间
     *
     * @return
     */
    public String getNowString() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_FORMAT));
    }

    /**
     * 获取指定格式的系统当前日期时间
     *
     * @param format 指定格式
     * @return
     */
    public String getNowString(String format) {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * 获取系统当前日期
     *
     * @return
     */
    public LocalDate getToday() {
        return LocalDate.now();
    }

    /**
     * 获取默认格式的系统当前时间
     *
     * @return
     */
    public String getTodayString() {
        return LocalDate.now().format(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT));
    }

    /**
     * 获取指定格式的系统当前时间
     *
     * @param format 指定格式
     * @return
     */
    public String getTodayString(String format) {
        return LocalDate.now().format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * 获取系统当前时间
     *
     * @return
     */
    public LocalTime getTime() {
        return LocalTime.now();
    }

    /**
     * 获取默认格式的系统当前时间
     *
     * @return
     */
    public String getTimeString() {
        return LocalTime.now().format(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT));
    }

    /**
     * 获取指定格式的系统当前时间
     *
     * @param format
     * @return
     */
    public String getTimeString(String format) {
        return LocalTime.now().format(DateTimeFormatter.ofPattern(format));
    }

    public LocalDateTime getLocalDateTime(String text, String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return LocalDateTime.parse(text, formatter);
    }

    /**
     * 格式化日期转为DateTime
     *
     * @param text
     * @param format
     * @return
     */
    public Date parseDateTime(String text, String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        LocalDateTime localDateTime = LocalDateTime.parse(text, formatter);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 格式化日期转为DateTime
     *
     * @param text
     * @param format
     * @return
     */
    public Date parseDate(String text, String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        LocalDate localDate = LocalDate.parse(text, formatter);
        return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    public String getDateTime(Date date, String format) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        return simpleDateFormat.format(date);
    }

    /**
     * 获取两个日期时间差（毫秒）
     *
     * @param start
     * @param end
     * @return
     */
    public long getDateTimesMillis(LocalDateTime start, LocalDateTime end) {
        Duration duration = Duration.between(start, end);
        return Math.abs(duration.toMillis());
    }

    public int getAge(String birthday) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT);
        LocalDate birthDate = LocalDate.parse(birthday, formatter);
        LocalDate today = LocalDate.now();
        return today.getYear() - birthDate.getYear();
    }

    /**
     * 取得指定日期以后若干天的日期。如果要得到以前的日期，参数用负数。
     *
     * @param date 基准日期
     * @param days 增加的日期数
     * @return 增加以后的日期
     */
    public Date addDays(Date date, int days) {
        return add(date, days, Calendar.DATE);
    }

    /**
     * @param date   增加的基数
     * @param dayNum 增加的数量
     * @param field  增加的单位，年，月或者日
     * @return 增加以后的日期
     */
    private Date add(Date date, int dayNum, int field) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(field, dayNum);
        return calendar.getTime();
    }

    /**
     * 计算年龄
     * @param birthday
     * @return
     */
    public int getAgeByBirth(Date birthday) {
        int age = 0;
        try {
            Calendar now = Calendar.getInstance();
            now.setTime(new Date());// 当前时间

            Calendar birth = Calendar.getInstance();
            birth.setTime(birthday);

            if (birth.after(now)) {// 如果传入的时间，在当前时间的后面，返回0岁
                age = 0;
            } else {
                age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR);
                if (now.get(Calendar.DAY_OF_YEAR) > birth.get(Calendar.DAY_OF_YEAR)) {
                    age += 1;
                }
            }
            return age;
        } catch (Exception e) {// 兼容性更强,异常后返回数据
            return 0;
        }
    }

    public String getYesterdayString() {
        String today = getTodayString();
        return getYesterdayString(today, DEFAULT_DATE_FORMAT);
    }

    public String getYesterdayString(String dateString, String format) {
        Date date = parseDate(dateString, format);
        Date yesterday = getYesterday(date);
        return getDateTime(yesterday, format);
    }

    public Date getYesterday() {
        return getYesterday(new Date());
    }

    public Date getYesterday(Date date) {
        return addDays(date, -1);
    }

    /**
     * 获取时间间隔
     * @param endTime(格式为 HH:mm)
     * @param startTime(格式为 HH:mm)
     * @return
     * @throws ParseException
     */
    public double getDiffHours(String endTime, String startTime) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        double diffTimes = sdf.parse(endTime).getTime() - sdf.parse(startTime).getTime();
        return diffTimes / (1000 * 60 * 60); //返回以小时计算
    }

    public Date getClockTime(String clockTime, String recordDate) {
        if (StringUtils.isBlank(clockTime) || clockTime.length() < 5) {
            return null;
        }
        if (StringUtils.isBlank(recordDate)) {
            recordDate = getTodayString();
        }

        int hours = Integer.parseInt(clockTime.substring(0, 2));
        int days = 0;
        if (hours >= 24) {
            days = hours / 24;
        }

        String times = recordDate + " " + clockTime + ":00";
        if (days > 0) {
            Date date = addDays(parseDate(recordDate, DEFAULT_DATE_FORMAT), days);
            times = getDateTime(date, DEFAULT_DATE_FORMAT) + " " + getRemainderHourBy24Hours(hours) + clockTime.substring(2) + ":00";
        }
        return parseDateTime(times, DEFAULT_DATETIME_FORMAT);
    }

    public String getRemainderHourBy24Hours(int hours) {
        int reminder = hours % 24;
        if (reminder <= 9) {
            return "0" + reminder;
        }
        return String.valueOf(reminder);
    }

    public boolean checkIsNextDay(String clockTime) {
        if (StringUtils.isBlank(clockTime) || clockTime.length() < 5) {
            return false;
        }
        int hours = Integer.parseInt(clockTime.substring(0, 2));
        return hours >= 24;
    }

    public Date getMiddleTime(Date startTime, Date endTime) {
        long timeMills = (endTime.getTime() + startTime.getTime()) / 2;
        return new Date(timeMills);
    }

    public String getClockTimeStr(Date date,String recordDate) {
        String dateStr = getDateTime(date, DEFAULT_DATETIME_FORMAT);
        Date compareDate = parseDateTime(recordDate + DEFAULT_DAY_TIME_END, DateUtil.DEFAULT_DATETIME_FORMAT);
        String clockTime = dateStr.substring(11, 16);
        if (compareDate.compareTo(date) >= 0) {
            return clockTime;
        }
        else {
            int hours = Integer.parseInt(clockTime.substring(0, 2));
            hours = hours + 24;
            return hours + clockTime.substring(2);
        }
    }

    public String getTomorrowStr(String datestr) {
        Date date = parseDate(datestr, DEFAULT_DATE_FORMAT);
        Date tomorrow = getTomorrow(date);
        return getDateTime(tomorrow, DEFAULT_DATE_FORMAT);
    }

    /**
     * 返回给定日期中的明天（后一天）的日期
     *
     * @param date
     *            基准日期
     * @return 明天的日期
     */
    public Date getTomorrow(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 减去1天，得到的即前一天
        calendar.add(Calendar.DATE, 1);
        return calendar.getTime();
    }

    public Date getDateTimeByTimeZone(String timeZoneId) {
        if (StringUtils.isBlank(timeZoneId)) {
            timeZoneId = "Asia/Chongqing";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_DATETIME_FORMAT);
        sdf.setTimeZone(TimeZone.getTimeZone(timeZoneId));  // 设置时区
        Date date = new Date();
        String dateStr = sdf.format(date);
        return this.parseDateTime(dateStr, DEFAULT_DATETIME_FORMAT);
    }

    public Date getCurrentDateOfStartTime() {
        String currentDate = this.getTodayString();
        return this.parseDateTime(currentDate  + DEFAULT_DAY_TIME_START, DEFAULT_DATETIME_FORMAT);
    }

    /**相隔天数
     * 计算两个日期相隔天数。 用第一个日期减去第二个。如果前一个日期小于后一个日期，则返回负数
     *
     * @param one
     *            第一个日期数，作为基准
     * @param two
     *            第二个日期数，作为比较
     * @return 两个日期相隔天数
     */
    public long getDays(Date start, Date end){
        Date d1 = null;
        Date d2 = null;
        try {
            d1= this.parseDate(this.getDateTime(start, DEFAULT_DATE_FORMAT), DEFAULT_DATE_FORMAT);
            d2= this.parseDate(this.getDateTime(end, DEFAULT_DATE_FORMAT), DEFAULT_DATE_FORMAT);
        }catch(Exception e) {
            e.printStackTrace();
        }

        long daysBetween=(d1.getTime()-d2.getTime())/(24 * 60 * 60 * 1000);
        if (daysBetween < 0) {
            daysBetween = 0;
        }
        return daysBetween;
    }

    public static void main(String[] args) {
//		System.out.println(DateUtil.getInstance().getAge("1990-11-16"));
//
//        Date date = DateUtil.getInstance().addDays(new Date(), -2);
//        System.out.println(DateUtil.getInstance().parseDateTime("2023-08-08 00:00:00","yyyy-MM-dd HH:mm:ss"));
        Date date = DateUtil.getInstance().getClockTime("06:00", "2023-09-22");
        System.out.println(DateUtil.getInstance().getDateTime(date,"yyyy-MM-dd HH:mm:ss"));
    }


}